home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / vbdatabs / tree.cpp < prev    next >
C/C++ Source or Header  |  1999-03-17  |  12KB  |  456 lines

  1. // ------------------------------- //
  2. // -------- Start of File -------- //
  3. // ------------------------------- //
  4. // ----------------------------------------------------------- // 
  5. // C++ Source Code File Name: tree.cpp
  6. // Compiler Used: MSVC40, DJGPP 2.7.2.1, GCC 2.7.2.1, HP CPP 10.24
  7. // Produced by: Doug Gaer
  8. // File Creation Date: 11/07/1996
  9. // Date Last Modified: 03/17/1999
  10. // ----------------------------------------------------------- // 
  11. // ------------- Program description and details ------------- // 
  12. // ----------------------------------------------------------- // 
  13. /*
  14. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
  15. THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE
  16. IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE,
  17. YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
  18. CORRECTION.
  19.  
  20. This is a simple class implementation of a binary search tree
  21. used to create a tree of character strings. The char * data type
  22. in the TreeNode class is used as a pointer to a pre-allocated
  23. strings. The tree structure itself stores a hierarchal collection
  24. of nodes. Each node stores a pointer to a unique character string
  25. along with left and right pointers to other nodes in the tree.
  26. */
  27. // ----------------------------------------------------------- // 
  28. #include <iostream.h>
  29. #include <string.h>
  30.  
  31. class Tnode; // Forward class name
  32.  
  33. // VisitFunc is a pointer to void(Tnode *Node) that points to
  34. // a visit function used to process node data during tree traversals
  35. typedef void (*VisitFunc)(Tnode *Node); 
  36.  
  37. // (T)ree (N)ode base class
  38. class Tnode
  39. {
  40. public:
  41.   Tnode() { right = left = 0; data = 0; }
  42.   Tnode(char *key, Tnode *l = 0, Tnode *r = 0) {
  43.     data = strdup(key); left = l; right = r; 
  44.   }
  45.   
  46. public:
  47.   char *data;   // data for this tree 
  48.   Tnode *right; // subtree to the right 
  49.   Tnode *left;  // subtree to the left 
  50. };
  51.  
  52. // Binary Search (T)ree class
  53. class Tree : public Tnode
  54. {
  55. public:
  56.   Tree() { root = 0; }
  57.   ~Tree() { Clear(); }
  58.   Tree(const Tree &t) { this->Copy(t); }
  59.   void operator=(const Tree &t) { this->Copy(t); }
  60.   
  61. public:
  62.   int Add(char *key);
  63.   int Remove(char *key);
  64.   int Find(char *key);
  65.   void Clear();
  66.   int Copy(const Tree &t);
  67.   void PrintTree(VisitFunc Visit) { PrintInOrder(root, Visit); }
  68.   int GetHeight() { return Height(root); }
  69.   
  70. private: // Functions for internal processing only
  71.   Tnode *SearchForParent(Tnode *node, char *key, Tnode *&parent, int &side);
  72.   Tnode *Insert(Tnode *&root, char *key, int &exists);
  73.   Tnode *DetachNode(Tnode *&root, Tnode *node, Tnode *parent, int side);
  74.   Tnode *GetParentOfSuccessor(Tnode *node);
  75.   Tnode *Detach(Tnode *&root, char *key);
  76.   int Delete(Tnode *&root, char *key);
  77.   void PrintInOrder(Tnode *tree, VisitFunc Visit);
  78.   void DeleteTree(Tnode *t);
  79.   Tnode *DupTree(Tnode *t);
  80.   int Height(Tnode *t);
  81.   
  82. private:
  83.   Tnode *root; // Pointer to the top of the tree 
  84. };
  85.  
  86. int Tree::Add(char *key)
  87. // Add an entry to the tree. 
  88. {
  89.   int exists;
  90.   Insert(root, key, exists);
  91.   return exists == 0; // Return true if the key did not already exist
  92. }
  93.  
  94. int Tree::Remove(char *key)
  95. // Remove a node from the tree.
  96. // Returns zero if the node does not exist.
  97. {
  98.   return Delete(root, key);
  99. }
  100.  
  101. void Tree::Clear()
  102. // Clear the tree.
  103. {
  104.   DeleteTree(root);
  105.   root = 0;
  106. }
  107.  
  108. int Tree::Find(char *key)
  109. // Search the tree for matching entry 
  110. {
  111.   Tnode *parent;
  112.   int side;
  113.  
  114.   // Search the tree
  115.   Tnode *node = SearchForParent(root, key, parent, side);
  116.  
  117.   return node != 0; // Return true if the matching node is found
  118. }
  119.  
  120. int Tree::Copy(const Tree &t)
  121. // Copy tree t into the tree object that invoked the call. 
  122. {
  123.   Clear();
  124.   Tnode *r = DupTree(t.root);
  125.  
  126.   if(r) {
  127.     root = r; // Tree was copied from the bottom up
  128.     return 1;
  129.   }
  130.   return 0; // Tree was not copied
  131. }
  132.  
  133. Tnode *Tree::Insert(Tnode *&root, char *key, int &exists)
  134. // Insert a new node into the tree. Returns the matching node,
  135. // new or old and may modify the root pointer.
  136. {
  137.   Tnode *parent;
  138.   int side;
  139.  
  140.   // Look for a place to insert the node
  141.   Tnode *node = SearchForParent(root, key, parent, side);
  142.  
  143.   if(node == 0) { // Node does not exist in the tree
  144.     node = new Tnode(key);
  145.     if(parent) {
  146.       if(side) parent->right = node; else parent->left = node;
  147.     }
  148.     else // No parent, so this is the new root
  149.       root = node;
  150.     
  151.     exists = 0;
  152.   }
  153.   else
  154.     exists = 1;
  155.  
  156.   return node;
  157. }
  158.  
  159. Tnode *Tree::SearchForParent(Tnode *node, char *key, Tnode *&parent, int &side)
  160. // Returns the parent of the matching node, as well as the node itself. 
  161. // Each node to the left is smaller then the given node, and each node
  162. // to right is larger.
  163. {
  164.   parent = 0;
  165.   while(node) {
  166.     if(strcmp(key, node->data) == 0) break;
  167.     parent = node;
  168.     if(strcmp(key, node->data) < 0) { // Node is smaller
  169.       side = 0;
  170.       node = node->left;
  171.     }
  172.     else { // Node is larger
  173.       side = 1;
  174.       node = node->right;
  175.     }
  176.   }
  177.   return node;
  178. }
  179.  
  180. Tnode *Tree::DetachNode(Tnode *&root, Tnode *node, Tnode *parent, int side)
  181. // Detach the node with parent from the tree. The node is the left
  182. // child if side equals zero or right child if side equals one.
  183. // Returns a pointer to the node.
  184. {
  185.   Tnode *psucc; // Parent of successor
  186.   Tnode *replacement;
  187.  
  188.   if(node) {
  189.     if(node->left == 0 || node->right == 0) {
  190.       // At lease one child is null, so use the other as the replacement
  191.       replacement = (node->left) ? node->left : node->right;
  192.     }
  193.     else { // Neither child is null
  194.       psucc = GetParentOfSuccessor(node); // Guaranteed not to be null
  195.       if(psucc == node) { // Immediate successor
  196.     replacement = psucc->right;
  197.       }
  198.       else {
  199.     // Detach replacement from its current loaction and
  200.         // relocate it to where node used to be
  201.     replacement = psucc->left;
  202.     psucc->left = psucc->left->right;
  203.         replacement->right = node->right;
  204.       }
  205.  
  206.       // Finish reloacting replacement to where node used to be
  207.       replacement->left = node->left;
  208.     }
  209.  
  210.     if(parent) { // Fix parent of node to point to replacement
  211.       if(side)
  212.         parent->right = replacement; else parent->left = replacement;
  213.     }
  214.     else root = replacement; // No parent, so node was the root
  215.   }
  216.   return node;
  217. }
  218.  
  219. Tnode *Tree::GetParentOfSuccessor(Tnode *node)
  220. // Used by the Tree::DetachNode() function to find the parent of
  221. // the successor node. Returns zero if no successor is found.
  222. {
  223.   Tnode *parent = 0;
  224.  
  225.   // Go right once, then all the way to the left
  226.   Tnode *q = node->right;
  227.   if(q) {
  228.     parent = node;
  229.     while(q->left) {
  230.       parent = q;
  231.       q = q->left;
  232.     }
  233.   }
  234.   return parent;
  235. }
  236.  
  237. Tnode *Tree::Detach(Tnode *&root, char *key)
  238. // Detaches the node matching key from the tree.
  239. {
  240.   int side;
  241.   Tnode *parent, *node;
  242.   node = SearchForParent(root, key, parent, side);
  243.   return DetachNode(root, node, parent, side);
  244. }
  245.  
  246. int Tree::Delete(Tnode *&root, char *key)
  247. // Deletes the node from the tree. 
  248. // Returns zero if the node does not exist.
  249. {
  250.   Tnode *node = Detach(root, key);
  251.   delete node;
  252.   return node != 0;
  253. }
  254.  
  255. void Tree::DeleteTree(Tnode *t)
  256. // Recursive function used to clear the tree from the bottom up.
  257. {
  258.   if(t == 0) return;
  259.   if(t->left == 0) return; else DeleteTree(t->left);
  260.   if(t->right == 0) return; else DeleteTree(t->right);
  261.   delete t;
  262. }
  263.  
  264. void Tree::PrintInOrder(Tnode *tree, VisitFunc Visit)
  265. // Visit each node of tree Tree in in-order, (first the Left
  266. // subtree, then the parent, then the Right subtree), with 
  267. // tail recursion removed
  268. {
  269.   while(tree) {
  270.     PrintInOrder(tree->left, Visit);
  271.     Visit(tree);
  272.     tree = tree->right;
  273.   }
  274. }
  275.  
  276. Tnode *Tree::DupTree(Tnode *t)
  277. // Recursive function that to duplicates a tree using
  278. // postorder traversal.
  279. {
  280.   if(t == 0) return 0;
  281.   Tnode *l = DupTree(t->left);
  282.   Tnode *r = DupTree(t->right);
  283.   return new Tnode(t->data, l, r);
  284. }
  285.  
  286. int Tree::Height(Tnode *t)
  287. // The height of a tree is the maximum of the height of
  288. // its two su